﻿' Copyright © Microsoft Corporation.  All Rights Reserved.
' This code released under the terms of the 
' Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
Imports Microsoft.VisualBasic
Imports System
Imports System.Diagnostics
Imports System.IO
Imports System.Net
Imports System.Reflection
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Resources
Imports System.Xml

Namespace Microsoft.Expression.Encoder.PlugInLoader

	Public Class PlugInLoaderFailedException
		Inherits Exception
		Public Sub New()
			MyBase.New()
		End Sub
		Public Sub New(ByVal message As String)
			MyBase.New(message)
		End Sub
		Public Sub New(ByVal message As String, ByVal exp As Exception)
			MyBase.New(message, exp)
		End Sub
	End Class

	Friend Class PlugInLoader
		Private uiThreadObject As Control
		Private webClient As WebClient
		Private targetAssemblyName As String
		Private assemblyTarget As System.Reflection.Assembly

		Friend Event PlugInLoadCompleted As EventHandler(Of OpenReadCompletedEventArgs)

		Friend Sub New()
			Debug.WriteLine("PlugInLoader()")
		End Sub

		Friend Sub New(ByVal uiThreadObject As Control)
			Debug.WriteLine("PlugInLoader(Control uiThreadObject)")
			Me.uiThreadObject = uiThreadObject
		End Sub

		Private Sub LoadAssembly(ByVal source As String, ByVal streamInfo As StreamResourceInfo)
			Debug.WriteLine("PlugInLoader.LoadAssembly(" & source & ", " & streamInfo.ToString() & " )")

			Dim asmPart As New AssemblyPart()
			Dim loadedAssembly As System.Reflection.Assembly = asmPart.Load(streamInfo.Stream)
			If 0 = String.Compare(source, Me.targetAssemblyName, StringComparison.OrdinalIgnoreCase) Then
				Me.assemblyTarget = loadedAssembly
			End If
		End Sub

		Private Sub AppManifestLoader(ByVal xap As Stream)
			Debug.WriteLine("PlugInLoader.AppManifestLoader( xap length=" & xap.Length.ToString())

			Dim manifestStreamReader As New StreamReader(Application.GetResourceStream(New StreamResourceInfo(xap, Nothing), New Uri("AppManifest.xaml", UriKind.Relative)).Stream)

			Dim appManifestReader As XmlReader = XmlReader.Create(manifestStreamReader)
			Do While appManifestReader.Read()
				If (appManifestReader.NodeType = XmlNodeType.Element) AndAlso (0=String.Compare(appManifestReader.Name, "AssemblyPart", StringComparison.OrdinalIgnoreCase)) AndAlso (appManifestReader.HasAttributes) Then
					Dim source As String = appManifestReader.GetAttribute("Source")
					Dim streamInfo As StreamResourceInfo = Application.GetResourceStream(New StreamResourceInfo(xap, "application/binary"), New Uri(source, UriKind.Relative))
					If Me.uiThreadObject IsNot Nothing Then
						Me.uiThreadObject.Dispatcher.BeginInvoke(Function() AnonymousMethod1(source, streamInfo))
					Else
						LoadAssembly(source, streamInfo)
					End If
				End If
			Loop
		End Sub
		
		Private Function AnonymousMethod1(ByVal source As String, ByVal streamInfo As StreamResourceInfo) As Object
			LoadAssembly(source, streamInfo)
			Return Nothing
		End Function

		Private Sub XAPReadCompleted(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)
			Debug.WriteLine("PlugInLoader.XAPReadCompleted()")

			' Check for error conditions
			If Not e.Cancelled Then
				If e.Error Is Nothing Then
					AppManifestLoader(e.Result)
				End If

				If Me.PlugInLoadCompletedEvent IsNot Nothing Then
					RaiseEvent PlugInLoadCompleted(sender, e)
				End If
			End If

			Me.webClient = Nothing
		End Sub

		Friend Sub Load(ByVal uriXAP As Uri, ByVal targetAssemblyNameParameter As String)
			Debug.WriteLine("PlugInLoader.Load(" & uriXAP.ToString() & ", " & targetAssemblyName & " )")

			Me.assemblyTarget = Nothing
			Me.targetAssemblyName = targetAssemblyNameParameter

			Me.webClient = New WebClient()
			AddHandler webClient.OpenReadCompleted, AddressOf XAPReadCompleted
			Me.webClient.OpenReadAsync(uriXAP)
		End Sub

		Friend Sub LocalLoad(ByVal localXapStream As Stream, ByVal targetAssemblyNameParameter As String)
			Debug.WriteLine("PlugInLoader.LocalLoad(" & localXapStream.Length.ToString() & ", " & targetAssemblyName & " )")

			Me.assemblyTarget = Nothing
			Me.targetAssemblyName = targetAssemblyNameParameter
			AppManifestLoader(localXapStream)
		End Sub

		Friend ReadOnly Property Ready() As Boolean
			Get
				Return Me.assemblyTarget IsNot Nothing
			End Get
		End Property

		Friend Function CreateObject(ByVal className As String) As Object
			Debug.WriteLine("PlugInLoader.CreateObject(" & className & " )")

			Dim message As String = String.Empty
			Try
				If Me.Ready Then
					Return Me.assemblyTarget.CreateInstance(className)
				End If
			Catch mme As MissingMethodException
				message = mme.ToString()
				Debug.WriteLine("CreateObject failed:" & message)
			End Try
			Throw New PlugInLoaderFailedException("CreateObject:" & message)
		End Function
	End Class
End Namespace